Functional Decorator

테커레이터 패턴은 클래스를 적용대상으로 하는 것이 일반적이지만, 함수에도 동등하게 적용할 수 있다.

함수 실행 전, 후로 로깅을 남기는 로깅 컴포넌트
struct Logger{
function<void()> func;
string name;
Logger(const function<void()>& func, const string& name): func(func), name(name) {}
void operator()() const {
cout<<"Entering "<<name <<endl;
func();
cout<<"Exiting "<<name <<endl;
}
};
//
Logger([](){ cout<<"Hello"<<endl;}, "HelloFunction")();
std::function이 아닌 템플릿 인자로 함수를 전달
template <typename Func>
struct Logger2{
Func func;
string name;
Logger2(const Func& func, const string& name): func(func), name(name) {}
void operator()() const {
cout<<"Entering "<<name<<endl;
func();
cout<<"Exiting "<<name<<endl;
}
};
template <typename Func>
auto make_logger2(Func func, const string& name){
return Logger2<Func>{ func, name };
}
//
auto call=make_logger2([](){ cout<<"Hello!"<<endl; }, "HelloFunction");
call();
사용하는 함수의 리턴값을 사용하는 데코레이터 함수
double add(double a, double b){
cout<<a<<"+"<<b<<"="<<(a+b)<<endl;
return a+b;
}
template <typename R, typename ...Args> // R
struct Logger3<R(Args...)>{ // Logger2 ( )
Logger3(function<R(Args...)> func, const string& name): func(func), name(name) {}
R operator()(Args... args){
cout<<"Entering "<<name<<endl;
R result=func(args...);
cout<<"Exiting "<<name<<endl;
return result;
}
function<R(Args ...)> func;
string name;
};
template <typename R, typename ...Args>
auto make_logger3(R (*func)(Args...), const string& name){
return Logger3<R(Args...)>(
std::function<R(Args...)>(func), name);
}
//
auto logged_add=make_logger3(add, "Add");
auto result=logged_add(2, 3);